package cn.com.sinux.spring.utils;

import cn.com.sinux.spring.commons.TreeNode;
import cn.com.sinux.spring.commons.TreeNodeHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * Created with IntelliJ IDEA.
 * User: liuhai
 * Date: 13-1-31
 * Time: 下午12:07
 * To change this template use File | Settings | File Templates.
 */
public class TreeNodeUtils {

    private static Logger logger = LoggerFactory.getLogger(TreeNodeUtils.class);

    /**
     * 初始化树
     *
     * @param nodes 散列节点
     * @return 组装后的树形
     */
    public static <T extends TreeNode> List<T> buildTree(final List<T> nodes, TreeNodeHelper<T> treeNodeHelper) {
        List<T> _nodes = new ArrayList<T>(nodes);
        if (_nodes.isEmpty()) {
            return _nodes;
        }
        List<T> tree = new LinkedList<T>();
        _group(tree, _nodes, treeNodeHelper);
        return tree;
    }

    /**
     * 便利树的所有节点
     *
     * @param nodes 树节点
     * @param treeNodeHelper 树节点操作帮助
     * @param <T> 泛型
     */
    public static <T extends TreeNode> void ergodicTree(final List<T> nodes, TreeNodeHelper<T> treeNodeHelper) {
        if (ValidatorUtils.isArrayNotEmpty(nodes)) {
            for (T t : nodes) {
                if (treeNodeHelper.doValidate(t)) {
                    treeNodeHelper.doOperate(t);
                }
                ergodicTree(t.getChildren(), treeNodeHelper);
            }
        }
    }

    private static <T extends TreeNode> void _reset(List<T> results, final List<T> nodes){
        if (ValidatorUtils.isArrayNotEmpty(nodes)){
            results.addAll(nodes);
            for(T node : nodes){
                _reset(results, node.getChildren());
            }
        }
    }


    /**
     * 还原树节点为list
     *
     * @param nodes 树节点
     * @param <T> 泛型
     */
    public static <T extends TreeNode> List<T> reset(final List<T> nodes) {
        List<T> results = new ArrayList<T>();
        _reset(results, nodes);
        for(T t : results){
            t.setChildren(null);
        }
        return results;
    }

    /**
     * 递归调用，对树节点排序
     */
    private static <T extends TreeNode> void sortTree(List<T> nodes, final TreeNodeHelper<T> treeNodeHelper) {
        if (nodes != null && nodes.size() > 1) {
            Collections.sort(nodes, new Comparator<T>() {
                public int compare(T o1, T o2) {
                    return compareTo(o1, o2, treeNodeHelper);
                }
            });
        }
    }

    /**
     * 排序
     *
     * @param o1
     * @param o2
     * @return
     */
    private static <T extends TreeNode> int compareTo(T o1, T o2, TreeNodeHelper<T> treeNodeHelper) {
        return treeNodeHelper.compare(o1, o2);
    }

    /**
     * 判断a是否是b的孩子节点
     *
     * @param a 树形节点
     * @param b 树形节点b
     * @return
     */
    public static <T extends TreeNode> boolean isChildren(T a, T b, TreeNodeHelper<T> treeNodeHelper) {
        return b.getId().equals(treeNodeHelper.getParentId(a));
    }

    private static void setChildren(TreeNode a, TreeNode b) {
        List<TreeNode> children = (List) a.getChildren();
        if (children != null && children.contains(b)) {
            return;
        }
        if (children == null) {
            children = new ArrayList<TreeNode>();
        }
        children.add(b);
        a.setChildren(children);
    }

    public static void main(String[] args) {

    }


    private static <T extends TreeNode> boolean hasChildren(TreeNode node, List<T> nodes, TreeNodeHelper<T> treeNodeHelper) {
        for (T _node : nodes) {
            if (node.getId().equals(treeNodeHelper.getParentId(_node))) {
                return true;
            }
        }
        return false;
    }

    private static <T extends TreeNode> List<T> _findAllLeaves(List<T> nodes, TreeNodeHelper<T> treeNodeHelper) {
        List<T> leaves = new LinkedList<T>();
        for (T node : nodes) {
            if (!hasChildren(node, nodes, treeNodeHelper)) {
                leaves.add(node);
            }
        }
        return leaves;
    }

    private static <T extends TreeNode> void _group(List<T> root, List<T> nodes, TreeNodeHelper<T> treeNodeHelper) {
        if (nodes.isEmpty()) {
            return;
        }
        if (nodes.size() == 1) {
            root.add(nodes.get(0));
            Collections.reverse(root);
            return;
        }
        List<T> leaves = _findAllLeaves(nodes, treeNodeHelper);
        nodes.removeAll(leaves);
        if (treeNodeHelper.sortEnable()) {
            sortTree(leaves, treeNodeHelper);
        }
        for (T node : leaves) {
            boolean isRoot = true;
            for (T node2 : nodes) {
                if (isChildren(node, node2, treeNodeHelper)) {
                    setChildren(node2, node);
                    isRoot = false;
                    break;
                }
            }
            if (isRoot) {
                root.add(node);
            }
        }
        leaves = null;
        _group(root, nodes, treeNodeHelper);
    }
}
